home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Graphics Plus
/
Graphics Plus.iso
/
general
/
raytrace
/
rayshade
/
graphtal.lzh
/
Graphtal.Amiga
/
Sphere.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-11-19
|
3KB
|
148 lines
/*
* Sphere.C - methods for sphere manipulations.
*
* Copyright (C) 1992, Christoph Streit (streit@iam.unibe.ch)
* University of Berne, Switzerland
* Copyright (C) 1989, 1991, Craig E. Kolb
* All rights reserved.
*
* This software may be freely copied, modified, and redistributed
* provided that this copyright notice is preserved on all copies.
*
* You may not distribute this software, in whole or in part, as part of
* any commercial product without the express consent of the authors.
*
* There is no warranty or other guarantee of fitness of this software
* for any purpose. It is provided solely "as is".
*
*/
#include "Sphere.h"
//___________________________________________________________ Sphere
Sphere::Sphere(real radius, const Vector& position)
: r(radius), center(position)
{
rsqr = r*r;
}
GeoObject* Sphere::create(real radius, const Vector& position)
{
if (radius < EPSILON)
return NULL;
return new Sphere(radius, position);
}
/*
* Compute the intersection between a ray and a sphere.
* This algorithm is adapted from Craig Kolbs rayshade.
*/
int Sphere::intersect(const Ray& ray, real minDist, real& maxDist)
{
real xadj, yadj, zadj;
real b, t, s;
intersectionTests++;
/*
* Translate ray origin to object space and negate everything.
* (Thus, we translate the sphere into ray space, which saves
* us a couple of negations below.)
*/
xadj = center[0] - ray.getOrig()[0];
yadj = center[1] - ray.getOrig()[1];
zadj = center[2] - ray.getOrig()[2];
/*
* Solve quadratic equation.
*/
b = xadj*ray.getDir()[0] + yadj*ray.getDir()[1] + zadj*ray.getDir()[2];
t = b*b - xadj*xadj - yadj*yadj - zadj*zadj + rsqr;
if (t < 0.)
return FALSE;
t = sqrt(t);
/*
* we may hit the sphere twice, test both cases
*/
s = b - t;
if (s > minDist) {
if (s < maxDist) {
maxDist = s;
return TRUE;
}
return FALSE;
}
s = b + t;
if (s > minDist && s < maxDist) {
maxDist = s;
intersections++;
return TRUE;
}
return FALSE;
}
/*
* Compute sphere normal.
*/
Vector Sphere::normal(const Vector& p) const
{
return (p-center)/r;
}
/*
* tesselate splits the sphere into polygons.
*/
PolygonList* Sphere::tesselate(const BoundingBox&)
{
PolygonList* polys = tesselation(center, r, 10);
if (trans != NULL) {
for (register long i=0; i<polys->count(); i++)
polys->item(i)->transform(*trans);
}
return polys;
}
/*
* General sphere tesselation.
*/
PolygonList* Sphere::tesselation(const Vector& pos, real r, int res)
{
real delta = M_PI/res;
PolygonList* polySphere = new PolygonList(3*res);
Vector A, B, C, D;
for (real alpha=0; alpha < 2*M_PI; alpha += delta) {
A = B = Vector(0,0,-r)+pos;
for (real beta=-M_PI_2+delta; beta<=M_PI_2-delta; beta += delta) {
C = computeSurfacePoint(alpha+delta, beta)*r+pos;
D = computeSurfacePoint(alpha, beta)*r+pos;
if (A==B)
polySphere->append(new Polygon(A, C, D));
else
polySphere->append(new Polygon(A, B, C, D));
A=D; B=C;
}
polySphere->append(new Polygon(A, B, Vector(0,0,r)+pos));
}
return polySphere;
}
Vector Sphere::computeSurfacePoint(real alpha, real beta)
{
real sin_a, cos_a, sin_b, cos_b;
SinCos(alpha, sin_a, cos_a);
SinCos(beta, sin_b, cos_b);
return Vector(cos_a*cos_b, sin_a*cos_b, sin_b);
}